#include <windows.h>

#include "lib.h"
#include "AppStub.h"

CAppStub::CAppStub()
{
	chInst = (HINSTANCE)0;
	chWnd = (HWND)0;
	chParent = (HWND)0;
	cGameInited = false;
}

void
CAppStub::Init(HINSTANCE hInst, const String& sCmdLine, HWND hParent, const String& AppName,
	HANDLE hBack, uint32 ExStyle, uint32 Style, int32 Width, int32 Height)
{
	chInst = hInst;
	chWnd = (HWND)0;
	chParent = hParent;
	cCmdLine = sCmdLine;
	cGameInited = false;

	lstrcpy(cClass, (const uint16*)AppName);
	lstrcat(cClass, TEXT("Class"));
	
	InitInstance(AppName, hBack, ExStyle, Style, Width, Height);
}

CAppStub::~CAppStub(void)
{
	DestroyInstance();
}

void
CAppStub::InitInstance
(
	const String& AppName,
	HANDLE hBack,
	uint32 ExStyle,
	uint32 Style,
	int32 Width,
	int32 Height
)
{
    WNDCLASS wc;

    wc.style = CS_DBLCLKS;
    wc.lpfnWndProc = TopWinProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 4;
    wc.hInstance = chInst;
    wc.hIcon = LoadIcon(chInst, AppName);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground  = (HBRUSH)(hBack ? hBack : GetStockObject(WHITE_BRUSH));
    wc.lpszMenuName = NULL;
    wc.lpszClassName = cClass;

    if (!RegisterClass(&wc))
		return;

	if (Style == 0)
	{
		Style = 0
			| WS_VISIBLE
			| WS_OVERLAPPED
			| WS_CAPTION
			| WS_SYSMENU
			| WS_MINIMIZEBOX
			| WS_MAXIMIZEBOX
			| WS_THICKFRAME
		;
	}

	const uint16* cAppName = (const uint16*)AppName;
	chWnd = CreateWindowEx
	(
		ExStyle,
		cClass,
		cAppName,
		Style,
		CW_USEDEFAULT, CW_USEDEFAULT,	// x, y
		Width, Height,
		chParent,		// parent window
		NULL,			// menu handle
		chInst,
		NULL			// create parms
	);
		    
    if (chWnd)
	{
		SetWindowLong(chWnd, GWL_USERDATA, (LONG)this);
		UpdateWindow(chWnd);
	}
}

void
CAppStub::DestroyInstance(void)
{
	UnregisterClass(cClass, chInst);
}

int32
CAppStub::WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
	{
		case WM_CLOSE:
			DestroyWindow(hWnd);
			break;

		case WM_DESTROY:
			SetWindowLong(chWnd, GWL_USERDATA, 0);

			KillGame();
			
			chWnd = (HWND)0;
			PostQuitMessage(0);
			break;

		default:
			return DefWindowProc(hWnd, Msg, wParam, lParam);
	}

    return 0L;
}

LONG FAR PASCAL
CAppStub::TopWinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	CAppStub *This = (CAppStub *)GetWindowLong(hWnd, GWL_USERDATA);

	if (This && This->cGameInited)
		return (LONG)This->WinProc(hWnd, Msg, wParam, lParam);
	else
		return DefWindowProc(hWnd, Msg, wParam, lParam);
}

int
CAppStub::Run(void)
{
    MSG msg;

	if (!chWnd)
		return 0;

	if (!InitGame())
		return 0;

	while (GetMessage(&msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 1;
}

//
// ------------------------------ CCAppTimer ----------------------------------
//

CAppTimer::CAppTimer()
{
}

void
CAppTimer::Init(HINSTANCE hInst, const String& lpCmdLine, HWND hParent, int32 TimeOutMilliSec,
	const String& AppName, HANDLE hBack, uint32 ExStyle, uint32 Style,
	int32 Width, int32 Height)
{
	CAppStub::Init(hInst, lpCmdLine, hParent, AppName, hBack, ExStyle, Style, Width, Height);

	cTimeout = TimeOutMilliSec;

	if (chWnd)
		SetTimer(chWnd, 1, cTimeout, NULL);
}


int32
CAppTimer::WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
		case WM_TIMER:
			GameLoop();
			break;

		case WM_DESTROY:
			KillTimer(hWnd, 1);
			break;

		default:
			break;
	}

	return CAppStub::WinProc(hWnd, Msg, wParam, lParam);
}

//
// ------------------------------- CCAppSpin ----------------------------------
//

CAppSpin::CAppSpin()
{
	cQuit = false;
}

LONG 
CAppSpin::WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
		case WM_DESTROY:
			cQuit = true;
			break;

		default:
			break;
	}

	return CAppStub::WinProc(hWnd, Msg, wParam, lParam);
}

int
CAppSpin::Run(void)
{
    MSG msg;

	if (!chWnd)
		return 0;

	if (!InitGame())
		return 0;

	while (1)
	{
		while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if (GetMessage(&msg, NULL, 0, 0) > 0)
				DispatchMessage(&msg);
			else
				cQuit = true;
		}

		if (cQuit)
			break;

		GameLoop();
	}

	return 1;
}
